package tx

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"longmen/server/config/global"
	"longmen/server/pkg/common/helper/encrypt"
	string2 "longmen/server/pkg/common/helper/string"
	time2 "longmen/server/pkg/common/helper/timehelper"
	"longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/db/redis/cache"
	"net/http"
	"net/url"
	"path"
	"strings"
	"time"

	"github.com/tencentyun/cos-go-sdk-v5"
)

func genBucketUrl(cosBucket, cosRegion string) string {
	fUrl := fmt.Sprintf("https://%s.cos.%s.myqcloud.com", cosBucket, cosRegion)
	//log.Println(fUrl)
	return fUrl
}

// DeleteObject 删除对象
func DeleteObject(objUrl string) (err error) {
	tmpKeys, err := GetTempKeys()
	if err != nil {
		return
	}
	bUrl := genBucketUrl(tmpKeys.Bucket, tmpKeys.Region)

	if strings.Index(objUrl, bUrl) != 0 {
		return errors.New("url错误")
	}

	u, _ := url.Parse(bUrl)
	b := &cos.BaseURL{BucketURL: u}
	c := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:     tmpKeys.Credentials.TmpSecretId,  // 用户的 SecretId，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
			SecretKey:    tmpKeys.Credentials.TmpSecretKey, // 用户的 SecretKey，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
			SessionToken: tmpKeys.Credentials.Token,
		},
	})
	name := strings.TrimPrefix(objUrl, bUrl+"/")
	_, err = c.Object.Delete(context.Background(), name)
	return
}

// PutObject 上传对象
func UploadFile(name string, f io.Reader) (fileUrl string, err error) {
	tmpKeys, err := GetTempKeys()
	if err != nil {
		return
	}
	u, _ := url.Parse(genBucketUrl(tmpKeys.Bucket, tmpKeys.Region))
	b := &cos.BaseURL{BucketURL: u}
	c := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:     tmpKeys.Credentials.TmpSecretId,  // 用户的 SecretId，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
			SecretKey:    tmpKeys.Credentials.TmpSecretKey, // 用户的 SecretKey，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
			SessionToken: tmpKeys.Credentials.Token,
		},
	})

	// 在第5位插入字符串
	modifiedContent := encryptFile(f)
	fileSuffix := path.Ext(name)
	name = encrypt.GenHashWithLength(32) + fileSuffix
	_, err = c.Object.Put(context.Background(), name, modifiedContent, nil)
	url := c.Object.GetObjectURL(name)
	return "https://" + url.Host + url.Path, nil
}

func encryptFile(file io.Reader) io.Reader {
	buffer := make([]byte, 1024)
	var content []byte
	for {
		n, err := file.Read(buffer)
		if err != nil {
			break // 读取完毕或出错
		}
		content = append(content, buffer[:n]...)
	}
	modifiedContent := insertStringAtPosition(content, encrypt.GenHashWithLength(9), 4)
	// 将修改后的内容写回文件
	return bytes.NewReader(modifiedContent)
}

func insertStringAtPosition(original []byte, insert string, position int) []byte {
	if position < 0 || position > len(original) {
		return original
	}
	return append(original[:position], append([]byte(insert), original[position:]...)...) //original[0:len(insert)],
}

func GetTempKeys() (*TmpKeys, error) {
	tempKeys := TmpKeys{}
	if tempKeys.GetCache() {
		//return &tempKeys, nil
	}

	configPri := cache.GetConfigPri()
	configPub := cache.GetConfigPub()
	sts := new(QcloudSTS)
	config := map[string]interface{}{}
	config["url"] = "https://sts.tencentcloudapi.com/"
	config["domain"] = "sts.tencentcloudapi.com"
	config["proxy"] = ""
	config["secretId"] = configPri.QcloudSecretid   // 固定密钥
	config["secretKey"] = configPri.QcloudSecretkey // 固定密钥
	config["bucket"] = configPri.CosBucket          // 换成你的 bucket
	config["region"] = configPri.CosRegion          // 换成 bucket 所在园区
	config["durationSeconds"] = 1800                // 密钥有效期
	config["allowPrefix"] = "*"                     // 这里改成允许的路径前缀，可以根据自己网站的用户登录态判断允许上传的具体路径，例子： a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
	// 密钥的权限列表。简单上传和分片需要以下的权限，其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
	config["allowActions"] = []string{"name/cos:PutObject", "name/cos:DeleteObject"} // 简单上传, 删除
	// 获取临时密钥，计算签名
	tempKeysMp, err := sts.GetTempKeys(config)
	if err != nil {
		return nil, err
	}
	tempKeysMp["bucket"] = configPri.CosBucket
	tempKeysMp["region"] = configPri.CosRegion
	tempKeysMp["filename"] = time.Now().Format(time2.TIME_LAYOUT_FORMAT_2) + util.I2S(string2.RandInt(10000, 99999))
	tempKeysMp["imgDomain"] = configPub.ImgDomain
	b, _ := json.Marshal(tempKeysMp)
	_ = json.Unmarshal(b, &tempKeys)
	global.Log.Debugf("tempKeys:%v", tempKeys)
	defer tempKeys.SetCache()
	return &tempKeys, nil
}

type TmpKeys struct {
	Credentials struct {
		TmpSecretId  string `json:"TmpSecretId"`
		TmpSecretKey string `json:"TmpSecretKey"`
		Token        string `json:"Token"`
	} `json:"Credentials"`
	Expiration  time.Time `json:"Expiration"`
	ExpiredTime int       `json:"ExpiredTime"`
	RequestId   string    `json:"RequestId"`
	StartTime   int       `json:"startTime"`
	Bucket      string    `json:"bucket"`
	Region      string    `json:"region"`
	Filename    string    `json:"filename"`
	ImgDomain   string    `json:"imgDomain"`
}

func (t *TmpKeys) GetKey() string {
	return fmt.Sprintf("TxCosTmpKeys")
}

func (t *TmpKeys) SetCache() {
	b, _ := json.Marshal(*t)
	global.GetRds().Set(t.GetKey(), b, t.Expiration.Sub(time.Now()))
}

func (t *TmpKeys) GetCache() bool {
	b, _ := global.GetRds().Get(t.GetKey()).Bytes()
	if len(b) <= 0 {
		return false
	}
	err := json.Unmarshal(b, t)
	t.Filename = time.Now().Format(time2.TIME_LAYOUT_FORMAT_2) + util.I2S(string2.RandInt(10000, 99999))
	return err == nil

}
